golang 您所在的位置:网站首页 golang 线程安全 map golang

golang

2023-08-26 15:11| 来源: 网络整理| 查看: 265

1.数组

非线程安全

示例:

package main import ( "fmt" "sync" "time" ) var ( array = new([10]int32) slice = make([]string, 0) mm = make(map[string]interface{}) ) func main() { array[0] = 1 array[1] = 2 array[2] = 3 fmt.Println("array = ", array) wg := sync.WaitGroup{} wg.Add(4) go func() { defer wg.Done() array[0] = 10 fmt.Println("go1", array) }() go func() { defer wg.Done() array[0] = 222 fmt.Println("go2", array) }() go func() { defer wg.Done() array[0] = 333 fmt.Println("go3", array) }() go func() { defer wg.Done() wg.Wait() }() time.Sleep(time.Second * 5) } array = &[1 2 3 0 0 0 0 0 0 0] go3 &[222 2 3 0 0 0 0 0 0 0] go1 &[10 2 3 0 0 0 0 0 0 0] go2 &[10 2 3 0 0 0 0 0 0 0]

2.切片

非线程安全的

package main import ( "fmt" "sync" "time" ) var ( array = new([10]int32) slice = make([]int, 0) mm = make(map[string]interface{}) ) func main() { wg := sync.WaitGroup{} // rw := sync.Mutex{} for i := 0; i < 10000; i++ { wg.Add(1) go func() { defer wg.Done() // rw.Lock() slice = append(slice, 88) // rw.Unlock() }() } wg.Add(1) go func() { defer wg.Done() wg.Wait() }() time.Sleep(time.Second * 5) fmt.Println("slice = ", len(slice),cap(slice)) } 如上代码,每次执行结果都不一样,说明是非线程安全的。 2.切片指定索引 package main import ( "fmt" "sync" ) func main() { // 指定索引存储 sl := make([]int, 100) wg := sync.WaitGroup{} for index := 0; index < 100; index++ { k := index wg.Add(1) go func(num int) { sl[num] = num wg.Done() }(k) } wg.Wait() fmt.Printf("final len(sl)=%d cap(sl)=%d\n", len(sl), cap(sl)) } 结果是每次都一样,表明切片都是支持并发的,但是存在读写数据覆盖情况,实际使用,不能达到预期效果。 《***》综上结论:当指定索引使用切片时,切片是支持并发读写索引区的数据的,但是索引区的数据在并发时会被覆盖的;当不指定索引切片时,并且切片动态扩容时,并发场景下扩容会被覆盖,所以切片是不支持并发的。 《+++》实际使用的时,可以枷锁,channel,或者sync.map替代,总是确保数据能达到预期结果即可。

3.map

非线程安全的

package main import ( "fmt" "sync" "time" ) var ( array = new([10]int32) slice = make([]int, 0) mm = make(map[int]int, 0) ) func main() { wg := sync.WaitGroup{} rw := sync.Mutex{} for i := 0; i < 10000; i++ { wg.Add(1) go func() { defer wg.Done() rw.Lock() mm[666] = i rw.Unlock() }() } wg.Add(1) go func() { defer wg.Done() wg.Wait() }() time.Sleep(time.Second * 5) fmt.Println("mm[666] = ", mm[666]) } //不枷锁会报错。

4.切片作为参数传递

     a.官方给的文档说明,go中的所有传递都是值传递,但是实际中,在基础类型的切片作为参数传递是,使用的是深拷贝,如下代码:

func modify(s []string) { s[0] = "hello" } func main() { var tl []string tl = make([]string, 4) tl[0] = "foo" modify(tl) fmt.Println(tl[0]) } 输出结果: hello

 如上代码,说明原来切片的内容被修改了,足以说明,切片基础类型使用的是深拷贝处理的。

   b.但是在切片追加元素的时候,如果超出容量,会触发扩容机制,内部会重新生成一个更大的切片将原来的数据拷贝过来。这样就会造成在发生扩容的时候原切片跟扩容后生成的切片就没有了任何关联了。如下:

func modify(s []string) { s = append(s, "world") // 触发扩容机制 } func main() { var tl []string tl = make([]string, 1) tl[0] = "foo" modify(tl) fmt.Println(tl[0]) // 该处输出原来切片的内容 } 输出结果: foo

使用切片是,一定要小心注意此等问题,不然会出现不可预期的错误。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有